//
//  RequestManager.m
//  Xinjuxin
//
//  Created by 廖挺 on 16/5/29.
//  Copyright © 2016年 liaoting. All rights reserved.
//

#import "RequestManager.h"
#import <AFNetworking.h>
#import "MKHttpResponse.h"
#import "NSData+MKBaseLib.h"
#import "MKBaseAppConfig.h"
#import "NSString+MKBaseLib.h"

static NSString *appVer = @"";


@interface RequestManager ()
@property (copy, nonatomic) NSString *host_url;
@property (strong ,nonatomic) NSMutableDictionary *requestDict; //存放目前还在请求的标示值
@property (strong ,nonatomic) NSNumber *recordedRequestId; //最后一次发出请求得到的唯一标示值
@end


@implementation RequestManager

#pragma - mark init
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    static id object = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        object = [super allocWithZone:zone];
    });
    return object;
}

+ (instancetype)ShareManager {
    return [[RequestManager alloc] init];
}

- (instancetype)init {
    if (self = [super init]) {
        if (APP_BUILD)
            _host_url = HOST_TEST_URL;
        else
            _host_url = HOST_BUSINESS_URL;
        appVer = [[MKBaseAppConfig new] getAppVersion];
    }
    return self;
}

/**
 *  懒加载请求管理单例的id字典
 *
 *  @return
 */
- (NSMutableDictionary *)requestDict {
    if (!_requestDict) {
        _requestDict = [NSMutableDictionary dictionary];
    }
    return _requestDict;
}

/**
 *  获取唯一性的requestId
 *
 *  @return
 */
- (NSNumber *)generateRequestId {
    if (!_recordedRequestId) {
        _recordedRequestId = @(1);
    } else {
        if ([_recordedRequestId integerValue] == NSIntegerMax) {
            _recordedRequestId = @(1);
        } else {
            _recordedRequestId = @([_recordedRequestId integerValue] + 1);
        }
    }
    return _recordedRequestId;
}

#pragma mark - request
/**
 *  请求数据成功后操作
 *
 *  @param requestId      数据请求id
 *  @param task
 *  @param responseObject 请求返回数据
 *  @param completion
 */
- (void)successRequestId:(NSNumber *_Nonnull)requestId
                    task:(NSURLSessionDataTask *_Nonnull)task
          responseObject:(id _Nullable)responseObject
              completion:(void (^)(MKHttpResponse *response))completion
       requestAgainBlock:(commontVoidBlock)requestAgainBlock {
    NSURLSessionDataTask *storedTask = self.requestDict[requestId];
    if (!storedTask)
        // 如果这个operation是被cancel的，那就不用处理回调了。
        return;
    else
        [self.requestDict removeObjectForKey:requestId];
    [self filterError:responseObject connectionError:nil completion:completion requestAgainBlock:requestAgainBlock];
}

/**
 *  请求数据失败后操作
 *
 *  @param requestId  数据请求id
 *  @param task
 *  @param error      请求失败返回数据
 *  @param completion
 */
- (void)failureRequestId:(NSNumber *_Nonnull)requestId
                    task:(NSURLSessionDataTask *_Nonnull)task
                   error:(NSError * _Nonnull)error
              completion:(void (^)(MKHttpResponse *response))completion
       requestAgainBlock:(commontVoidBlock)requestAgainBlock {
    NSURLSessionDataTask *storedTask = self.requestDict[requestId];
    if (!storedTask)
        return;
    else
        [self.requestDict removeObjectForKey:requestId];
    [self filterError:nil connectionError:error completion:completion requestAgainBlock:requestAgainBlock];
}

/**
 *  对成功/失败数据的解析
 *
 *  @param data            请求成功的数据
 *  @param connectionError 请求失败的数据
 *  @param completion
 */
- (void)filterError:(NSData *)data
    connectionError:(NSError *)connectionError
         completion:(void (^)(MKHttpResponse *response))completion
  requestAgainBlock:(commontVoidBlock)requestAgainBlock {
    if (!completion)
    {
        return ;
    }
    MKHttpResponse *res = [[MKHttpResponse alloc] init];
    res.connectionError = connectionError;
    res.originData = data;
    if (connectionError != nil)
    {
        res.errorMsg = @"网络错误!";
        res.errorType = MKHttpErrorTypeLocal;
        completion(res);
        return;
    }
    NSDictionary *responseObject = [data baseLib_jsonObject];
    NSString *msg = responseObject[@"msg"];
    res.responseCode = [responseObject[@"code"] integerValue];
    //将10000定义为成功了
    if (res.responseCode != 10000)
    {
        if (msg.length == 0 || (res.responseCode >= 40000 && res.responseCode < 50000)) {
            msg = @"服务器出错了!";
        } else if (res.responseCode >50000) {
            if (res.responseCode == 50001 || res.responseCode == 50002) {
                [self getCommonSessionTokenWithBlock:requestAgainBlock];
            } else if (res.responseCode == 50003 || res.responseCode == 50004) {
                [self refreshAccessTokenWithBlock:requestAgainBlock];
            } else if (res.responseCode == 50005 || res.responseCode == 50006) {
                [[NSNotificationCenter defaultCenter] postNotificationName:@"login" object:nil];
            }
            return;
        }
        res.errorMsg = msg;
        res.errorType = MKHttpErrorTypeRemote;
        completion(res);
        return;
    }
    res.responseDictionary = responseObject;
    completion(res);
}

/**
 *  使用post请求数据
 *
 *  @param urlString  url字符串api
 *  @param parameters 参数字典（可以为nil）
 *  @param completion
 *
 *  @return
 */
- (NSInteger)postUrlString:(NSString *)urlString
                parameters:(NSDictionary *_Nullable)parameters
                completion:(void (^)(MKHttpResponse *response))completion
         requestAgainBlock:(commontVoidBlock)requestAgainBlock {
    NSNumber *requestId = [self generateRequestId];
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/plain",nil];
    manager.responseSerializer = [AFHTTPResponseSerializer serializer];
    NSURLSessionDataTask *task = [manager POST:urlString parameters:parameters progress:^(NSProgress * _Nonnull uploadProgress) {
        DLog(@"%@",uploadProgress);
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        [self successRequestId:requestId task:task responseObject:responseObject completion:completion requestAgainBlock:requestAgainBlock];
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        [self failureRequestId:requestId task:task error:error completion:completion requestAgainBlock:requestAgainBlock];
    }];
    if (requestAgainBlock) {
      return [self postUrlString:urlString parameters:parameters completion:completion requestAgainBlock:requestAgainBlock];
    }
    self.requestDict[requestId] = task;
    return [requestId integerValue];
}

/**
 *  get请求数据
 *
 *  @param urlString  url字符串
 *  @param parameters 参数字典（可以为nil）
 *  @param completion
 *
 *  @return
 */
- (NSInteger)getUrlString:(NSString *)urlString
               parameters:(NSDictionary *_Nullable)parameters
               completion:(void (^)(MKHttpResponse *response))completion
        requestAgainBlock:(commontVoidBlock)requestAgainBlock {
    NSNumber *requestId = [self generateRequestId];
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/plain",nil];
    manager.responseSerializer = [AFHTTPResponseSerializer serializer];
    NSURLSessionDataTask *task = [manager GET:urlString parameters:parameters progress:^(NSProgress * _Nonnull downloadProgress) {
        DLog(@"%@",downloadProgress);
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        [self successRequestId:requestId task:task responseObject:responseObject completion:completion requestAgainBlock:requestAgainBlock];
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        [self failureRequestId:requestId task:task error:error completion:completion requestAgainBlock:requestAgainBlock];
    }];
    if (requestAgainBlock) {
       return [self getUrlString:urlString parameters:parameters completion:completion requestAgainBlock:requestAgainBlock];
    }
    self.requestDict[requestId] = task;
    return [requestId integerValue];
}

/**
 *  上传图片
 *
 *  @param arrayImageData 图片数据数组、不能为空
 *  @param fileName       图片文件名，和后台匹配
 *  @param urlString      url字符串
 *  @param parameters     其他参数
 *  @param completion     block
 *
 *  @return requestId
 */
- (NSInteger)uploadUrlString:(NSString *)urlString
                    fileName:(NSString *)fileName
                  parameters:( NSDictionary *_Nullable)parameters
              arrayImageData:(nonnull NSArray<NSData *> *)arrayImageData
              completion:(void (^)(MKHttpResponse *response))completion
       requestAgainBlock:(commontVoidBlock)requestAgainBlock {
    NSNumber *requestId = [self generateRequestId];
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/plain",nil];
    manager.responseSerializer = [AFHTTPResponseSerializer serializer];
    NSURLSessionDataTask *task = [manager POST:urlString parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        NSInteger i = 0;
        if (arrayImageData.count == 1) {
            NSData *imgData = arrayImageData[i];
            // name 字段必须和服务器端的名字一致
            [formData appendPartWithFileData:imgData
                                        name:fileName
                                    fileName:[NSString stringWithFormat:@"image.png"]
                                    mimeType:@"image/png"];
        }
        else {
            // 这边是个坑。。。图片为多个的时候，此设置就不能提交多张图片了，需要像下面设置才行
            for (NSData *imgData in arrayImageData) {
                [formData appendPartWithFileData:imgData
                                            name:[NSString stringWithFormat:@"image_%ld.png", (long)i]
                                        fileName:fileName
                                        mimeType:@"image/png"];
                i++;
            }
        }
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        DLog(@"%@",uploadProgress);
    } success:^(NSURLSessionDataTask *_Nonnull task, id  _Nullable responseObject) {
        [self successRequestId:requestId task:task responseObject:responseObject completion:completion requestAgainBlock:requestAgainBlock];
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        [self failureRequestId:requestId task:task error:error completion:completion requestAgainBlock:requestAgainBlock];
    }];
    if (requestAgainBlock) {
       return [self uploadUrlString:urlString fileName:fileName parameters:parameters arrayImageData:arrayImageData completion:completion requestAgainBlock:requestAgainBlock];
    }
    self.requestDict[requestId] = task;
    return [requestId integerValue];
}

/**
 *  除了上传文件以外的请求
 *
 *  @param urlString       url字符串
 *  @param requestLoadType 请求方式，一般为get/post
 *  @param parameters      参数字典
 *  @param completion
 *
 *  @return
 */
- (NSInteger)loadWithUrlString:(NSString *)urlString
               requestLoadType:(RequestLoadType)requestLoadType
                    parameters:(NSDictionary *_Nullable)parameters
                    completion:(void (^)(MKHttpResponse *response))completion
             requestAgainBlock:(commontVoidBlock)requestAgainBlock {
    switch (requestLoadType) {
        case RequestLoadTypeGet: {
          return [self getUrlString:urlString parameters:parameters completion:completion requestAgainBlock:requestAgainBlock];
            break;
        }
        case RequestLoadTypePost: {
           return [self postUrlString:urlString parameters:parameters completion:completion requestAgainBlock:requestAgainBlock];
            break;
        }
    }
}

#pragma - mark cancel
/**
 *  取消某个请求
 *
 *  @param requestId
 */
- (void)cancelRequestByRequestId:(NSNumber *)requestId {
    NSURLSessionDataTask *task = self.requestDict[requestId];
    if (!task) {
        return;
    }
    [task cancel];
    [self.requestDict removeObjectForKey:requestId];
}

/**
 *  取消某组请求
 *
 *  @param requestIdList
 */
- (void)cancelRequestByRequestIdList:(NSArray * _Nonnull)requestIdList {
    if (!requestIdList)
        return;
    for (NSNumber *requestId in requestIdList) {
        [self cancelRequestByRequestId:requestId];
    }
}

#pragma - 请求参数打包
/**
 *  将api组建成url字符串
 *
 *  @param api api
 *
 *  @return
 */
- (NSString *)buildUrlStringWithApi:(NSString *)api {
    NSString *na = [api copy];
    while (na.length > 0 && [[na substringToIndex:1] isEqualToString:@"/"])
    {
        na = [na substringFromIndex:1];
    }
    if (na.length == 0)
    {
        return _host_url;
    }
    return [_host_url stringByAppendingFormat:@"/%@", na];
}

/**
 *  创建参数字典
 *
 *  @param paramters api传入的参数字典
 *
 *  @return
 */
- (NSMutableDictionary *)disposeParamters:(NSDictionary *)paramters {
    NSMutableDictionary *p = [NSMutableDictionary dictionaryWithCapacity:paramters.count];
    [paramters enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop)
     {
         if (![key isKindOfClass:[NSString class]])
         {
             key = [NSString stringWithFormat:@"%@", key];
         }
         key = [key stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
         if (![obj isKindOfClass:[NSString class]])
         {
             obj = [NSString stringWithFormat:@"%@", obj];
         }
         p[key] = obj;
     }];
    p[@"app_key"] = APP_KEY;
    p[@"version"] = appVer;
    p[@"device_id"] = [MKBaseAppConfig MKUDID];
    p[@"format"] = @"json";
    p[@"session_token"] = [[ClientManager manager] getSessionToken];
    p[@"access_token"] = [[ClientManager manager] getAccessToken];
    p[@"server_version"] = MockuaiVersionCode;
    NSArray *a = [p.allKeys sortedArrayUsingSelector:@selector(compare:)];
    NSMutableString *s = [NSMutableString string];
    for (NSString *k in a)
    {
        [s appendFormat:@"&%@=%@", k, p[k]];
    }
    [s deleteCharactersInRange:NSMakeRange(0, 1)];
    NSString *ss = [NSString stringWithFormat:@"%@%@%@", APP_SECRET, s, APP_SECRET];
    p[@"api_sign"] = [ss baseLib_md5String];
    return p;
}

#pragma - mark 下面是具体的数据请求
/**
 *  获取sessionToken
 *
 *  @param block 调用block
 *
 *  @return
 */
- (NSInteger)getCommonSessionTokenWithBlock:(commontVoidBlock)block {
    NSInteger requestIdGetSessionToken = [self loadWithUrlString:[self buildUrlStringWithApi:METHOD_AUTH_SESSION_TOKEN_GET] requestLoadType:RequestLoadTypeGet parameters:nil completion:^(MKHttpResponse *response) {
        if (!response.errorMsg && response.responseCode == 10000) {
            [[ClientManager manager] saveSessionToken:response.mkResponseData[@"session_token"]];
            if (block) {
                block();
            }
        }
    } requestAgainBlock:block];
    return requestIdGetSessionToken;
}

/**
 *  refreshToken
 *
 *  @param block 调用block
 *
 *  @return
 */
- (NSInteger)refreshAccessTokenWithBlock:(commontVoidBlock)block {
    NSInteger requestIdGetSessionToken = [self loadWithUrlString:[self buildUrlStringWithApi:METHOD_AUTH_ACCESS_TOKEN_REFRESH] requestLoadType:RequestLoadTypePost parameters:@{@"refresh_token":[[ClientManager manager] getRefreshToken]} completion:^(MKHttpResponse *response) {
        if (!response.errorMsg && response.responseCode == 10000) {
            [[ClientManager manager] saveRefreshToken:response.mkResponseData[@"refresh_token"]];
            [[ClientManager manager] saveAccessToken:response.mkResponseData[@"access_token"]];
            if (block) {
                block();
            }
        }
    } requestAgainBlock:block];
    return requestIdGetSessionToken;
}


@end
